package nl.ru.rd.facedetection.nnbfd;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.Serializable;

/**
 * A mathematical object generally represented as an array of numbers.
 * 
 * @author Christiaan Thijssen s0814970
 * @author Kevin Reintjes s0814954
 * @author Wouter Geraedts (s0814857 - wgeraedts) PGP 66AA5935
 */
public class Matrix implements Serializable
{
	private static final long serialVersionUID = -10018161165289795L;
	/**
	 * Internal matrix storage.
	 */
	// Because of design choices in Java, we're using short and not bytes (no
	// unsigned bytes)
	private short[][] matrix;

	/**
	 * Creates a matrix with a specified width and height Method does not instantiate cells.
	 * 
	 * @param width
	 * @param height
	 */
	public Matrix(int width, int height)
	{
		this.matrix = new short[width][height];
	}

	/**
	 * Makes a 1:1 copy of the specified source matrix.
	 * 
	 * @param source
	 *            The matrix to be copied.
	 */
	public Matrix(Matrix source)
	{
		int height = source.getHeight();
		int width = source.getWidth();

		this.matrix = new short[width][height];
		for(int x = 0; x < width; x++)
			for(int y = 0; y < height; y++)
				this.matrix[x][y] = source.getValue(x, y);
	}

	/**
	 * @return Height of the matrix.
	 */
	public int getHeight()
	{
		if(this.getWidth() == 0)
			return 0;

		return this.matrix[0].length;
	}

	/**
	 * @return Width of the matrix.
	 */
	public int getWidth()
	{
		return this.matrix.length;
	}

	/**
	 * Gets the value of the specified matrixcell.
	 * 
	 * @param x
	 *            Column of the cell from which to get the value.
	 * @param y
	 *            Row of the cell from which to get the value.
	 * @return The value of the specified cell.
	 */
	public short getValue(int x, int y)
	{
		return this.matrix[x][y];
	}

	/**
	 * Sets the value of the specified matrixcell
	 * 
	 * @param x
	 *            Column of the cell from which to set the value.
	 * @param y
	 *            Row of the cell from which to set the value.
	 * @param value
	 *            The value for the specified cell.
	 */
	public void setValue(int x, int y, short value)
	{
		this.matrix[x][y] = value;
	}

	/**
	 * Convert the matrix to a grayscale BufferedImage.
	 * 
	 * @return A grayscale bufferdImage created from the cellvalues of this Matrix.
	 */
	public BufferedImage toImage()
	{
		int width = this.getWidth();
		int height = this.getHeight();

		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
		WritableRaster raster = image.getRaster();

		for(int x = 0; x < width; x++)
			for(int y = 0; y < height; y++)
				raster.setSample(x, y, 0, this.getValue(x, y));

		return image;
	}

	public String toString()
	{
		StringBuffer result = new StringBuffer();

		for(int x = 0; x < this.getWidth(); x++)
		{
			for(int y = 0; y < this.getHeight(); y++)
				result.append(Short.toString(this.getValue(x, y)) + " ");

			result.append("\n");
		}

		return result.toString();
	}
}